home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 85 / CD Temático 40 Febrero 2004.iso / DOS / ntfs / user / mkntfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-15  |  22.6 KB  |  754 lines

  1. /*  mkntfs - create NTFS format filesystems on block devices
  2.     Copyright 1999 by Steve Dodd <dirk@loth.demon.co.uk>
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of version 2 of the GNU General Public License as
  6.     published by the Free Software Foundation.
  7.  
  8.     This program is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See version 2
  11.     of the GNU General Public License for more details.
  12.  
  13.     You should have received a copy of version 2 of the GNU General
  14.     Public License along with this program; if not, write to the
  15.     Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
  16.     MA 02139, USA.
  17.  
  18.     Version: $Id: mkntfs.c,v 1.1.1.1 2001/02/11 16:12:51 kmaster Exp $
  19. */
  20.  
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #ifdef HAVE_GETOPT_H
  28. #include <getopt.h>
  29. #else
  30. #define getopt_long(a,v,o,ol,x)        getopt(a,v,o)
  31. #endif
  32. #ifdef HAVE_UNISTD_H
  33. #include <unistd.h>
  34. #endif
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <stdarg.h>
  38.  
  39. #include <fcntl.h>
  40. #include <errno.h>
  41.  
  42. #include "ntfstypes.h"
  43. #include "struct.h"
  44. #include "macros.h"
  45. #include "support.h"
  46. #include "util.h"
  47. #include "attr.h"
  48. #include "inode.h"
  49. #include "super.h"
  50. #include "dir.h"
  51. #include "attrtypes.h"
  52.  
  53. #include <sys/ioctl.h>
  54. #include <linux/hdreg.h>
  55. #include <linux/fs.h>
  56.  
  57. int verbose_flag = 0;   /* verbose mode defaults to off */
  58. int fd;                 /* file descriptor of block device */
  59. int cluster_size = 0;   /* cluster size in bytes */
  60. int sector_size = 512;  /* sector size in bytes */
  61. long sect_per_trk = 0;  /* sectors per track */
  62. int heads = 0;          /* heads */
  63. long dev_size;          /* size of device in 512 byte blocks */
  64. long max_lcn;           /* largest LCN */
  65. long mft_lcn = 1;       /* LCN of MFT */
  66. long mftmirr_lcn;       /* LCN of MFT mirror */
  67. int file_rec_size;      /* FILE record size in clusters */
  68. int indx_buf_size;      /* index buffer size in clusters */
  69. char *vol_label="";     /* volume label */
  70.  
  71. ntfs_volume *vol;       /* structure representing volume */
  72. ntfs_inode *mft_ino;    /* inode struct for $MFT */
  73. ntfs_inode *root_ino;   /* inode struct for root */
  74. ntfs_inode *boot_ino;   /* inode struct for $Boot */
  75.  
  76. void verbose( const char *fmt, ... )
  77. {
  78.     va_list args;
  79.  
  80.     if( verbose_flag ) {
  81.         va_start( args, fmt );
  82.         vprintf( fmt, args );
  83.         fflush( stdout );
  84.         va_end( args );
  85.     }
  86. }
  87.  
  88. void iso8859_2_uni( char *dest, const char *src )
  89. {
  90.     int i, len;
  91.  
  92.     len = strlen( src );
  93.     for( i = 0; i < len; i++ ) {
  94.         *dest++ = *src++;
  95.         *dest++ = '\0';
  96.     }
  97. }
  98.  
  99. void get_blkdev_info( void )
  100. {
  101.     if( ioctl( fd, BLKGETSIZE, &dev_size ) ) {
  102.         fprintf( stderr, "Couldn't get device size: %s\n",
  103.             strerror( errno ) );
  104.     }
  105.     
  106.     if( !cluster_size ) {
  107.         if( dev_size ) {
  108.             if( dev_size < 512 * 1024 * 2 )
  109.                 cluster_size = sector_size;
  110.             else if( dev_size < 1024 * 1024 * 2 )
  111.                 cluster_size = 1024;
  112.             else if( dev_size < 2048 * 1024 * 2 )
  113.                 cluster_size = 2048;
  114.             else
  115.                 cluster_size = 4096;
  116.         } else
  117.             cluster_size = 1024;
  118.     }
  119.  
  120.     if( cluster_size < sector_size )
  121.         cluster_size = sector_size;
  122.  
  123.     printf( "Sector size:\t\t\t%d\n", sector_size );
  124.     printf( "Cluster size:\t\t\t%d\n", cluster_size );
  125.  
  126.     if( cluster_size > 4096 )
  127.         printf( "Warning: large cluster sizes may cause problems with
  128.             compression.\n" );
  129.  
  130.     printf( "Device size:\t\t\t%ld sectors (%ld clusters)\n", dev_size
  131.             * ( sector_size / 512 ), dev_size *
  132.             ( cluster_size / 512 ) );
  133.  
  134.     file_rec_size = max( 1024 / cluster_size, 1 );
  135.     printf( "FILE record size:\t\t%d clusters (%ld bytes)\n", file_rec_size,
  136.         (long)file_rec_size * (long)cluster_size );
  137.  
  138.     indx_buf_size = max( 2048 / cluster_size, 1 );
  139.     verbose( "INDX buffer size:\t\t%d clusters (%ld bytes)\n", indx_buf_size,
  140.         (long)indx_buf_size * (long)cluster_size );
  141.  
  142.     max_lcn = ( dev_size / ( cluster_size / 512 ) ) - 1;
  143.     verbose( "Maximum cluster number:\t\t%ld\n", max_lcn );
  144.  
  145.     printf( "MFT starts at cluster:\t\t%ld\n", mft_lcn );
  146.  
  147.     mftmirr_lcn = max_lcn - ( file_rec_size * 4 ) + 1;      
  148.     printf( "Mirror of MFT at cluster:\t%ld\n", mftmirr_lcn );
  149.  
  150.     printf( "\n" );
  151. }
  152.  
  153. ntfs_inode *add_mft_entry( int ino )
  154. {
  155.     char *mftent;
  156.     ntfs_inode *new_ino;
  157.  
  158.     /* allocate mem for MFT entry */
  159.     mftent = calloc( file_rec_size, cluster_size );
  160.     ntfs_fill_mft_header( (ntfs_u8 *)mftent, file_rec_size * cluster_size,
  161.         cluster_size, 0 );
  162.  
  163.     /* insert fix ups */
  164.     ntfs_insert_fixups( (unsigned char *)mftent, sector_size );
  165.  
  166.     /* move to correct position in MFT */
  167.     lseek( fd, ( mft_lcn * cluster_size ) + ( ino * file_rec_size *
  168.         cluster_size ), SEEK_SET );
  169.  
  170.     /* write it */
  171.     write( fd, mftent, file_rec_size * cluster_size );
  172.  
  173.     free( mftent );
  174.  
  175.     /* read it back */
  176.  
  177.     new_ino = (ntfs_inode *)ntfs_malloc( sizeof( ntfs_inode ) );
  178.     ntfs_init_inode( new_ino, vol, ino );
  179.  
  180.     return new_ino;
  181. }
  182.  
  183.  
  184. void add_boot_file( void )
  185. {
  186.     ntfs_attribute *attr;
  187.     ntfs_runlist *rl;
  188.  
  189.     boot_ino = add_mft_entry( FILE_BOOT );
  190.  
  191.     ntfs_create_attr( boot_ino, ATTR_DATA, NULL, NULL, 0, &attr );
  192.     rl = ntfs_malloc( sizeof( ntfs_runlist ) );
  193.  
  194.     attr->resident = 0;
  195.     attr->allocated = attr->initialized = attr->size = 1 * cluster_size;
  196.     rl->len = 1;
  197.     rl->cluster = 0;                        /* boot cluster at LCN 0 */
  198.     attr->d.r.runlist = rl; attr->d.r.len = 1;
  199.  
  200.     /* flush to disk */
  201.     verbose( "Writing MFT entry for $Boot (%d)...", FILE_BOOT );
  202.     ntfs_update_inode( boot_ino );
  203.     verbose( "done.\n" );
  204. }
  205.  
  206. ntfs_attribute *create_name_attr( char *name, int hidden )
  207. {
  208.     ntfs_attribute *attr;
  209.     char *data;
  210.  
  211.     attr = calloc( sizeof( ntfs_attribute ), 1 );
  212.     data = calloc( 0x42 + strlen( name ) * 2, 1 );
  213.     attr->d.data = data; attr->size = 0x42 + strlen( name ) * 2;
  214.     iso8859_2_uni( data+0x42, name );
  215.     NTFS_PUTU8( data + 0x40, strlen( name ) );      /* file name len */     
  216.     NTFS_PUTU8( data + 0x41, 0 );                   /* POSIX name space */
  217.     NTFS_PUTU64( data + 0x38, 0x20 |
  218.         ( hidden ? 0x02 : 0 ) );                /* Arch + maybe hidden */
  219.     /* times */
  220.     NTFS_PUTU64( data + 0x8, ntfs_unixutc2ntutc( time( NULL ) ) );
  221.     NTFS_PUTU64( data + 0x10, ntfs_unixutc2ntutc( time( NULL ) ) );
  222.     NTFS_PUTU64( data + 0x18, ntfs_unixutc2ntutc( time( NULL ) ) );
  223.     NTFS_PUTU64( data + 0x20, ntfs_unixutc2ntutc( time( NULL ) ) );
  224.  
  225.     return attr;
  226. }
  227.     
  228. void dispose_temp_name( ntfs_attribute *attr )
  229. {
  230.     free( attr->d.data );
  231.     free( attr );
  232. }       
  233.  
  234. void add_root_ent( char *name, ntfs_inode *ino )
  235. {
  236.     ntfs_attribute *attr = create_name_attr( name, 1 );
  237.  
  238.     verbose( "Adding root entry `%s' for inode %d...", name, ino->i_number );
  239.     
  240.     ntfs_dir_add( root_ino, ino, attr );
  241.  
  242.     ntfs_update_inode( root_ino );
  243.  
  244.     dispose_temp_name( attr );
  245.     verbose( "done.\n" );
  246. }
  247.  
  248. void init_volume( void )
  249. {
  250.     ntfs_attribute *attr;
  251.     ntfs_inode *vol_ino;
  252.     char *vol_label_uni;
  253.     char vol_info[0xb];
  254.  
  255.     vol_ino = add_mft_entry( FILE_VOLUME );
  256.  
  257.     /* add volume label */
  258.     vol_label_uni = malloc( strlen( vol_label ) * 2 );
  259.     iso8859_2_uni( vol_label_uni, vol_label );
  260.     ntfs_create_attr( vol_ino, ATTR_VOLUME_NAME, NULL, vol_label_uni,
  261.         strlen( vol_label ) * 2, &attr );
  262.  
  263.     /* add volume information */
  264.     ntfs_create_attr( vol_ino, ATTR_VOLUME_INFORMATION, NULL, vol_info,
  265.         0xb, &attr );
  266.     
  267.     ntfs_update_inode( vol_ino );
  268.     add_root_ent( "$Volume", vol_ino );
  269.  
  270.     free( vol_label_uni );
  271.     free( vol_ino );
  272. }
  273.  
  274. struct attrdef {
  275.     const char *label;
  276.     ntfs_u64 type, flags;
  277.     ntfs_u64 min_size, max_size;
  278. };
  279.  
  280. struct attrdef attrdefs[] = {
  281.     { "$STANDARD_INFORMATION", ATTR_STANDARD_INFORMATION, AFLAG_INDEXABLE |
  282.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  283.     { "$ATTRIBUTE_LIST", ATTR_ATTRIBUTE_LIST, AFLAG_INDEXABLE |
  284.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  285.     { "$FILE_NAME", ATTR_FILE_NAME, AFLAG_INDEXABLE | AFLAG_NONRESIDENT,
  286.         ASIZE_MIN, ASIZE_MAX }, 
  287.     { "$VOLUME_VERSION", ATTR_VOLUME_VERSION, AFLAG_INDEXABLE |
  288.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  289.     { "$SECURITY_DESCRIPTOR", ATTR_SECURITY_DESCRIPTOR, AFLAG_INDEXABLE |
  290.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  291.     { "$VOLUME_NAME", ATTR_VOLUME_NAME, AFLAG_INDEXABLE | AFLAG_NONRESIDENT,
  292.         ASIZE_MIN, ASIZE_MAX }, 
  293.     { "$VOLUME_INFORMATION", ATTR_VOLUME_INFORMATION, AFLAG_INDEXABLE |
  294.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  295.     { "$DATA", ATTR_DATA, AFLAG_INDEXABLE | AFLAG_NONRESIDENT, ASIZE_MIN,
  296.         ASIZE_MAX} , 
  297.     { "$INDEX_ROOT", ATTR_INDEX_ROOT, AFLAG_INDEXABLE | AFLAG_NONRESIDENT,
  298.         ASIZE_MIN, ASIZE_MAX }, 
  299.     { "$INDEX_ALLOCATION", ATTR_INDEX_ALLOCATION, AFLAG_INDEXABLE |
  300.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  301.     { "$BITMAP", ATTR_BITMAP, AFLAG_INDEXABLE | AFLAG_NONRESIDENT, ASIZE_MIN,
  302.          ASIZE_MAX }, 
  303.     { "$SYMBOLIC_LINK", ATTR_SYMBOLIC_LINK, AFLAG_INDEXABLE |
  304.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  305.     { "$EA_INFORMATION", ATTR_EA_INFORMATION, AFLAG_INDEXABLE |
  306.         AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX }, 
  307.     { "$EA", ATTR_EA, AFLAG_INDEXABLE | AFLAG_NONRESIDENT, ASIZE_MIN,
  308.         ASIZE_MAX }
  309. };
  310.  
  311. int num_attrdefs = sizeof( attrdefs ) / sizeof( struct attrdef );
  312.  
  313. void init_attrdef( void )
  314. {
  315.     ntfs_attribute *attr;
  316.     ntfs_inode *attr_ino;
  317.     char *attr_rec;
  318.     int i;
  319.     ntfs_io io;
  320.  
  321.     attr_ino = add_mft_entry( FILE_ATTRDEF );
  322.     ntfs_create_attr( attr_ino, ATTR_DATA, NULL, NULL, 0, &attr );
  323.  
  324.     /* we seem to need to do this before adding data to the inode?
  325.        do we still need to do it after we finish writing the data? */
  326.     ntfs_update_inode( attr_ino );
  327.  
  328.     attr_rec = malloc( 0xa0 );
  329.     io.fn_get = ntfs_get; io.fn_put = ntfs_put;
  330.  
  331.     for( i = 0; i < num_attrdefs; i++ ) {
  332.  
  333.         /* probably not needed, but filesystem dumps are easier to
  334.             read if unused space isn't full of crap */
  335.         memset( attr_rec, 0, 0xa0 );
  336.  
  337.         iso8859_2_uni( attr_rec, attrdefs[i].label );
  338.         NTFS_PUTU16( attr_rec + strlen( attrdefs[i].label )
  339.             * 2, 0x0000 ); /* null-terminate */
  340.  
  341.         NTFS_PUTU64( attr_rec + 0x80, attrdefs[i].type );
  342.         NTFS_PUTU64( attr_rec + 0x88, attrdefs[i].flags );
  343.         NTFS_PUTU64( attr_rec + 0x90, attrdefs[i].min_size );
  344.         NTFS_PUTU64( attr_rec + 0x98, attrdefs[i].max_size );
  345.             
  346.         io.size = 0xa0; io.param = attr_rec;
  347.  
  348.         verbose( "Adding attribute `%s', type 0x%Lx, flags 0x%Lx...",
  349.             attrdefs[i].label, attrdefs[i].type, attrdefs[i].flags );
  350.  
  351.         ntfs_write_attr( attr_ino, ATTR_DATA, NULL, i * 0xa0, &io );
  352.         verbose( "done.\n" );
  353.     }
  354.  
  355.     ntfs_update_inode( attr_ino );
  356.     add_root_ent( "$AttrDef", attr_ino );
  357.     free( attr_rec );
  358.     free( attr_ino );
  359. }
  360.  
  361. void init_mftmirr( void )
  362. {
  363.     ntfs_attribute *attr;
  364.     ntfs_inode *mirr_ino;
  365.     char *mirror_data;
  366.     ntfs_io io;
  367.     ntfs_runlist rl;
  368.  
  369.     mirr_ino = add_mft_entry( FILE_MFTMIRR );
  370.     ntfs_create_attr( mirr_ino, ATTR_DATA, NULL, NULL, 0, &attr );
  371.  
  372.     /* force attribute to allocated area */
  373.  
  374.     attr->resident = 0; attr->allocated = cluster_size * file_rec_size * 4;
  375.     attr->size = attr->initialized = 0; attr->d.r.runlist = &rl;
  376.     attr->d.r.len = 1;
  377.     rl.cluster = mftmirr_lcn; rl.len = attr->allocated / cluster_size;
  378.     ntfs_update_inode( mirr_ino ); 
  379.  
  380.     /* read critical MFT entries and write to MFTMirr */
  381.  
  382.     mirror_data = malloc( attr->allocated );
  383.     io.size = attr->allocated;
  384.     io.param = mirror_data; io.fn_get = ntfs_get; io.fn_put = ntfs_put;
  385.     ntfs_read_attr( mft_ino, ATTR_DATA, NULL, 0, &io );
  386.     io.param = mirror_data; 
  387.     ntfs_write_attr( mirr_ino, ATTR_DATA, NULL, 0, &io );
  388.     free( mirror_data );
  389.  
  390.     ntfs_update_inode( mirr_ino );
  391.     add_root_ent( "$MFTMirr", mirr_ino );
  392.     free( mirr_ino );
  393. }
  394.  
  395. void init_empty( char *name, int inum )
  396. {
  397.     ntfs_attribute *attr;
  398.     ntfs_inode *ino;
  399.  
  400.     ino = add_mft_entry( inum );
  401.     ntfs_create_attr( ino, ATTR_DATA, NULL, NULL, 0, &attr );
  402.     ntfs_update_inode( ino );
  403.     add_root_ent( name, ino );
  404.     free( ino );
  405. }
  406.  
  407. void init_root( void )
  408. {
  409.     /* make new MFT record */
  410.     root_ino = add_mft_entry( FILE_ROOT );
  411.  
  412.     /* do dir stuff */
  413.     root_ino->attr[0x16] |= 2;      /* is directory */
  414.     ntfs_add_index_root( root_ino, ATTR_FILE_NAME );
  415.  
  416.     /* flush to disk */
  417.     verbose( "Adding root directory (indexed on type 0x%x, inode %d)...",
  418.         ATTR_FILE_NAME, FILE_ROOT );
  419.     ntfs_update_inode( root_ino );
  420.     verbose( "done.\n" );
  421.  
  422.     /* add entries */
  423.     add_root_ent( ".", root_ino );
  424.     add_root_ent( "$MFT", mft_ino );
  425.     add_root_ent( "$Boot", boot_ino );
  426. }
  427.     
  428.  
  429. void init_bitmap( void )
  430. {
  431.     ntfs_attribute *attr;
  432.     ntfs_inode *bitmap_ino; 
  433.     long dev_clusters;
  434.     ntfs_runlist *rl;
  435.     ntfs_cluster_t location;        /* these two for ntfs_alloc_clust */
  436.     int count;      
  437.  
  438.     /* make new MFT record */
  439.     bitmap_ino = add_mft_entry( FILE_BITMAP );
  440.  
  441.     /* create the attribute */
  442.  
  443.     ntfs_create_attr( bitmap_ino, ATTR_DATA, NULL, NULL, 0, &attr );
  444.     dev_clusters = dev_size / ( cluster_size / 512 ); /* num clusters */
  445.  
  446.     verbose( "%ld clusters on device, %ld bytes wasted.\n",
  447.         dev_clusters, ( dev_size - ( dev_clusters * ( cluster_size /
  448.         512 ) )  ) * 512 );
  449.  
  450.     attr->resident = 0;
  451.     attr->initialized = attr->size = ( dev_clusters + 7 ) / 8;
  452.     attr->allocated = ( ( attr->size + cluster_size - 1 ) / cluster_size )
  453.         * cluster_size;
  454.     rl = ntfs_malloc( sizeof( ntfs_runlist ) );
  455.     rl->len = attr->allocated / cluster_size;
  456.     rl->cluster = mftmirr_lcn - rl->len;    /* bitmap before MFT mirror */
  457.     attr->d.r.runlist = rl; attr->d.r.len = 1;
  458.  
  459.     verbose( "Allocated %d clusters (%d bytes) for bitmap at LCN %d\n",
  460.         rl->len, attr->allocated, rl->cluster );
  461.  
  462.     /* flush to disk */
  463.     ntfs_update_inode( bitmap_ino );
  464.  
  465.     /* now we have a bitmap inode, update struct */
  466.     vol->bitmap = bitmap_ino;
  467.  
  468.     /* clear bitmap */
  469.     ntfs_deallocate_clusters( vol, 0, dev_clusters );
  470.  
  471.     /* allocate cluster ranges we've used already */
  472.  
  473.     location = 0; count = 1;        /* boot cluster */
  474.     ntfs_allocate_clusters( vol, &location, &count, ALLOC_REQUIRE_LOCATION |
  475.         ALLOC_REQUIRE_SIZE );
  476.  
  477.     location = mft_lcn; count = 0x10 * file_rec_size; /* MFT */
  478.     ntfs_allocate_clusters( vol, &location, &count,
  479.          ALLOC_REQUIRE_LOCATION | ALLOC_REQUIRE_SIZE );
  480.  
  481.     location = mftmirr_lcn - rl->len; count = rl->len; /* bmap */
  482.     ntfs_allocate_clusters( vol, &location, &count,
  483.         ALLOC_REQUIRE_LOCATION | ALLOC_REQUIRE_SIZE );
  484.  
  485.     location = mftmirr_lcn; count = file_rec_size * 4; /* MFT mirror */
  486.     ntfs_allocate_clusters( vol, &location, &count,
  487.         ALLOC_REQUIRE_LOCATION | ALLOC_REQUIRE_SIZE );
  488.  
  489.  
  490.     add_root_ent( "$Bitmap", vol->bitmap );
  491. }       
  492.     
  493. int write_empty_mft( void )
  494. {
  495.     char *mftent;
  496.     int rc;
  497.     int attr_off;
  498.     char *attrs, *rl;
  499.     char mftbmap[2] = { 0xff, 0xff };
  500.     ntfs_attribute *attr;
  501.     int i;
  502.     ntfs_io io;
  503.  
  504.     mftent = calloc( file_rec_size, cluster_size );
  505.     
  506.     /* initialise MFT entry 0 */
  507.  
  508.     ntfs_fill_mft_header( (ntfs_u8 *)mftent, file_rec_size * cluster_size,
  509.         cluster_size, 0 );
  510.     attr_off = NTFS_GETU16( mftent+0x14 );          /* offset of attribs */
  511.     attrs = mftent + attr_off;                      /* location of attrs */
  512.  
  513.     /* insert $DATA attribute */
  514.     /* all this palaver is probably not needed - can we just leap in and
  515.         call Martin's routines straight away? */
  516.  
  517.     NTFS_PUTU32( attrs, ATTR_DATA );                /* type */
  518.     NTFS_PUTU32( attrs + 0x4, 0x49 );               /* length */
  519.     NTFS_PUTU8( attrs + 0x8, 0x01 );                /* not resident */
  520.     NTFS_PUTU8( attrs + 0x9, 0x00 );                /* name len = 0 */
  521.     NTFS_PUTU16( attrs + 0xA, 0x40 );               /* offset to content */
  522.     NTFS_PUTU16( attrs + 0xC, 0x0000 );             /* not compressed */
  523.     NTFS_PUTU16( attrs + 0xE, 0x0000 );             /* huh? */
  524.     NTFS_PUTU64( attrs + 0x10, 0x0 );               /* starting VCN */
  525.     NTFS_PUTU64( attrs + 0x18, 0x0 );               /* ending VCN */
  526.     NTFS_PUTU16( attrs + 0x20, 0x40 );              /* offset to run list */
  527.     NTFS_PUTU16( attrs + 0x22, 0x0000 );            /* no cengine */
  528.     NTFS_PUTU64( attrs + 0x28, 0x10 * file_rec_size *
  529.         cluster_size );                         /* we contain 16 file rec */
  530.     NTFS_PUTU64( attrs + 0x30, 0x10 * file_rec_size *
  531.         cluster_size );                         /* real size as above */
  532.     NTFS_PUTU64( attrs + 0x38, 0x10 * file_rec_size *
  533.         cluster_size    );                      /* init size as above */
  534.     
  535.     verbose( "Initial MFT size is 16 records (%d clusters, %d bytes)\n",
  536.             0x10 * file_rec_size, 0x10 * file_rec_size * cluster_size );
  537.  
  538.     /* name + run list start at 0x40 from attr start */
  539.     rl = attrs + 0x40;
  540.     NTFS_PUTU8( rl, 0x44 );                         /* sizeof(off,len)=4 */
  541.     NTFS_PUTU32( rl + 0x1, 0x10 * file_rec_size );
  542.     NTFS_PUTU32( rl + 0x5, mft_lcn );               /* 1st LCN of run */
  543.     
  544.     attrs = rl + 0x09;
  545.  
  546.     verbose( "$MFT data attribute (type 0x%x) run at LCN %d, length %d\n",
  547.         ATTR_DATA, mft_lcn, 0x10 * file_rec_size );
  548.  
  549.     /* mark end of attribs */
  550.     NTFS_PUTU32( attrs, 0xffffffff );
  551.  
  552.     ntfs_insert_fixups( (unsigned char*)mftent, sector_size );
  553.  
  554.     verbose( "Writing bootstrap MFT entry... " );
  555.  
  556.     lseek( fd, mft_lcn * cluster_size, SEEK_SET );
  557.     write( fd, mftent, file_rec_size * cluster_size );
  558.  
  559.     verbose( "done.\n" );
  560.  
  561.  
  562.     /* now things are initialised enough to hand over to Martin's
  563.         routines - phew */
  564.  
  565.     vol->mft = mftent;
  566.     mft_ino = (ntfs_inode *)ntfs_malloc( sizeof( ntfs_inode ) );
  567.     rc = ntfs_init_inode( mft_ino, vol, FILE_MFT );
  568.     vol->mft_ino = mft_ino;
  569.     if( rc ) {
  570.         fprintf( stderr, "Couldn't init inode for $MFT: %s\n",
  571.             strerror( rc ) );
  572.         return rc;
  573.     }
  574.  
  575.  
  576.     /* insert the bitmap attribute */
  577.     ntfs_create_attr( mft_ino, ATTR_BITMAP, NULL, &mftbmap, 2, &attr );
  578.  
  579.     /* write out null MFT entries for slots 1-15 */
  580.     verbose( "Writing 15 (0xf) empty MFT entries " );
  581.     for( i = 1; i < 16; i++ ) {     
  582.         ntfs_fill_mft_header( (ntfs_u8 *)mftent,
  583.             file_rec_size * cluster_size, cluster_size, 0 );
  584.         io.fn_get = ntfs_get; io.fn_put = ntfs_put;
  585.         io.size = file_rec_size * cluster_size;
  586.         io.param = mftent;
  587.         ntfs_write_attr( mft_ino, ATTR_DATA, NULL, file_rec_size *
  588.             cluster_size * i, &io );
  589.         verbose( "." );
  590.     }
  591.     verbose( " done.\n" );
  592.         
  593.     /* commit MFT entry */
  594.     verbose( "Flushing MFT info to disk... " );
  595.     ntfs_update_inode( mft_ino );
  596.     verbose( "done\n" );
  597.  
  598.     return 0;
  599. }
  600.     
  601.     
  602. void write_boot( void )
  603. {
  604.     char *bootblk;
  605.  
  606.     bootblk = calloc( cluster_size, 1 );
  607.     
  608.     NTFS_PUTU32( bootblk+3, *(int *)"NTFS" );       /* signature */
  609.     NTFS_PUTU16( bootblk+0xb, sector_size );        /* sector size */
  610.     NTFS_PUTU8( bootblk+0xd, cluster_size /         /* sectors per cluster */
  611.         sector_size );
  612.     NTFS_PUTU8( bootblk+0x15, 0xf8 );               /* media descriptor */
  613.     NTFS_PUTU16( bootblk+0x18, sect_per_trk );      /* sectors per track */
  614.     NTFS_PUTU16( bootblk+0x1a, heads );             /* no. of heads */
  615.     NTFS_PUTU16( bootblk+0x24, 0x0080 );            /* ??? */
  616.     NTFS_PUTU16( bootblk+0x26, 0x0080 );            /* ??? */
  617.     NTFS_PUTU64( bootblk+0x28, dev_size *
  618.         ( sector_size / 512 ) );                /* device size (sectors) */
  619.     NTFS_PUTU64( bootblk+0x30, mft_lcn );           /* LCN of MFT */
  620.     NTFS_PUTU64( bootblk+0x38, mftmirr_lcn );       /* LCN of mirror of MFT */
  621.     NTFS_PUTU32( bootblk+0x40, file_rec_size );     /* len of FILE record */
  622.     NTFS_PUTU32( bootblk+0x44, indx_buf_size );     /* len of INDX buffer */
  623.     NTFS_PUTU32( bootblk+0x48, 0x0f000f00 );        /* volume serial num */
  624.     NTFS_PUTU16( bootblk+0x1fe, 0xaa55 );           /* boot sector magic */
  625.     
  626.     /* copy to end of boot cluster */
  627.     if( cluster_size - 0x200 >= 0x200 ) {
  628.         memcpy( bootblk + cluster_size - 0x200, bootblk, 0x200 );
  629.         verbose( "Boot block info duplicated at offset 0x%x\n",
  630.              cluster_size - 0x200 );
  631.     }
  632.     
  633.     verbose( "Writing boot block... " );
  634.  
  635.     lseek( fd, 0, SEEK_SET );       /* seek to cluster 0 */
  636.     write( fd, bootblk, cluster_size );
  637.  
  638.     verbose( "done.\n" );
  639.  
  640.     /* init volume info */
  641.     vol = (ntfs_volume *)ntfs_malloc( sizeof( ntfs_volume ) );
  642.     ntfs_init_volume( vol, bootblk );
  643.     NTFS_FD(vol) = fd;
  644.  
  645.     free( bootblk );
  646. }       
  647.  
  648. char *short_opts="hVs:u:t:H:n:cvl:";
  649. #ifdef HAVE_GETOPT_H
  650. struct option options[]={
  651.     {"help",0,0,'h'},
  652.     {"version",0,0,'V'},
  653.     {"sectsize",1,0,'s'},
  654.     {"clustersize",1,0,'u'},
  655.     {"tracksize",1,0,'t'},
  656.     {"heads",1,0,'H'},
  657.     {"label",1,0,'n'},
  658.     {0,0,0,0}
  659. };
  660. #endif
  661.  
  662. static char const rcsid[] = "$Id: mkntfs.c,v 1.1.1.1 2001/02/11 16:12:51 kmaster Exp $";
  663.  
  664. char usage_str[]=
  665. "\nmkntfs " NTFS_VERSION "\n"
  666. "Usage: mkntfs [-cv] [-s sectsize] [-u clustersize] [-t sectors] [-H heads] \\\n"
  667. "        [-n label] [-l filename] device\n"
  668. "       mkntfs [-hV]\n"
  669. "  --sectsize, -s <n>\t\tSector size of media, default 512\n"
  670. "  --clustersize, -u <n>\t\tCluster size of new filesystem, default varies\n"
  671. "  --tracksize, -t <n>\t\tSectors per track, no default\n"
  672. "  --heads, -H <n>\t\tNumber of heads, no default\n"
  673. "  --label, -n <s>\t\tVolume label, no default\n"
  674. "  -c\t\t\t\tCheck the device for bad blocks first\n"
  675. "  -v\t\t\t\tVerbose output\n"
  676. "  -l <s>\t\t\tFile from which to read list of bad blocks\n"
  677. "  --help, -h\t\t\tDisplay this message\n"
  678. "  --version, -V\t\t\tDisplay version number\n"
  679. "\n"
  680. ;
  681.  
  682.  
  683. void usage(void)
  684. {
  685.     fprintf(stderr,usage_str);
  686. }
  687.  
  688. int main(int argc,char *argv[])
  689. {
  690.     int c;
  691.     char *device=0;
  692.  
  693.     opterr=1;
  694.     while((c=getopt_long(argc,argv,short_opts,options,NULL))>0)
  695.         switch(c) {
  696.         case 'u': cluster_size=strtol(optarg,NULL,0);break;
  697.         case 's': sector_size=strtol(optarg,NULL,0);break;
  698.         case 't': sect_per_trk=strtol(optarg,NULL,0);break;
  699.         case 'n': vol_label=optarg;break;
  700.         case 'h': usage();exit(0);break;
  701.         case 'V': printf("mkntfs " NTFS_VERSION "\n\t%s\n",rcsid);exit(0);break;
  702.         case 'c':
  703.         case 'l':
  704.             fprintf( stderr, "Sorry -c and -l not yet supported.\n" );
  705.             exit(1);
  706.             break;
  707.         case 'v': verbose_flag = 1; break;
  708.         default: usage();exit(1);
  709.         }
  710.  
  711.     if( argc - optind != 1 ) {
  712.         usage(); exit(1);
  713.     }
  714.  
  715.     device=argv[optind];
  716.  
  717.     fd = open( device, O_RDWR );
  718.     if( fd == -1 ) {
  719.         fprintf( stderr, "Couldn't open %s: %s\n", device,
  720.             strerror(errno) );
  721.         exit( 2 );
  722.     }
  723.     
  724.     printf( "\n" );
  725.  
  726.     get_blkdev_info();      /* get device info, calculate `things' */
  727.     write_boot();           /* write boot cluster based on above info */
  728.     write_empty_mft();      /* initialise the MFT */
  729.     add_boot_file();        /* add an MFT record for the boot cluster */
  730.  
  731.     init_root();            /* initialise the root directory */
  732.     init_bitmap();          /* initialise the volume bitmap */
  733.     init_volume();          /* initialise the volume info */
  734.     init_attrdef();         /* initialise attribute list */
  735.  
  736.     init_empty( "$LogFile", FILE_LOGFILE );
  737.     init_empty( "$BadClus", FILE_BADCLUS );
  738.     init_empty( "$Quota", FILE_QUOTA );
  739.     init_empty( "$UpCase", FILE_UPCASE );
  740.  
  741.     init_mftmirr();         /* make copy of important MFT records:
  742.                    do this last */
  743.  
  744.     close( fd );
  745.  
  746.     free( mft_ino );
  747.     free( vol->mft );
  748.     free( vol );
  749.  
  750.     verbose( "\n" );
  751.  
  752.     return 0;
  753. }
  754.